package com.ankang.util;

import com.ankang.entity.ChannelLevel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.charset.Charset;

public class ModbusTcpClientTow {

    private static final Logger log = LoggerFactory.getLogger(ModbusTcpClientTow.class);

    private static final int CONNECT_TIMEOUT_MS = 3000; // 连接超时
    private static final int READ_TIMEOUT_MS = 3000; // 读取超时
    static final int MAX_LIBRARY_BYTES = 100; // 字库最大字节数（可配置）

    // 显示器配置
    private final String ipAddress;
    private final int port;

    /**
     * 构造器（从ChannelLevel初始化显示器配置）
     * @param channelLevel 通道信息
     */
    public ModbusTcpClientTow(ChannelLevel channelLevel) {
        this.ipAddress = channelLevel.getDisplayIp();
        this.port = channelLevel.getDisplayPort();
        Assert.hasText(ipAddress, "显示器IP不能为空");
        Assert.isTrue(port > 0, "显示器端口必须大于0");
        log.info("初始化双字库显示器客户端 - IP: {}, 端口: {}", ipAddress, port);
    }


    public void sendMessages(String message1, String message2) {
        byte unitId = 0x01;
        Charset encoding = Charset.forName("GB2312");

        try {
            log.info("开始发送双字库消息 - 字库一: {}, 字库二: {}",
                    message1 != null ? message1 : "空",
                    message2 != null ? message2 : "空");

            // 字库一：完整保留所有字符
            sendFullContent(encoding, unitId, "字库一", (short) 0x0000, (short) 0x0005, message1);
            // 字库二：完整保留所有字符
            if (message2 != null) {
                sendFullContent(encoding, unitId, "字库二", (short) 0x00C8, (short) 0x00CD, message2);
            } else {
                log.info("字库二消息为空，跳过发送");
            }

            log.info("双字库消息发送流程完成");
        } catch (Exception e) {
            log.error("双字库消息发送失败", e);
        }
    }

    private void sendFullContent(
            Charset encoding,
            byte unitId,
            String libraryName,
            short propertyStart,
            short dataStart,
            String message
    ) throws IOException {
        Assert.notNull(message, "[" + libraryName + "] 发送内容不能为空");
        log.info("[{}] 原始发送内容: {}", libraryName, message);

        byte[] messageBytes = message.getBytes(encoding);
        int byteCount = messageBytes.length;
        log.debug("[{}] 原始字节数: {}", libraryName, byteCount);

        // 超长内容截断（按字节）
        if (byteCount > MAX_LIBRARY_BYTES) {
            byte[] newBytes = new byte[MAX_LIBRARY_BYTES];
            System.arraycopy(messageBytes, 0, newBytes, 0, MAX_LIBRARY_BYTES);
            messageBytes = newBytes;
            byteCount = MAX_LIBRARY_BYTES;
            log.warn("[{}] 内容超长，截断为 {} 字节", libraryName, byteCount);
        }

        // 确保偶数字节（补0）
        if (byteCount % 2 != 0) {
            byte[] newBytes = new byte[byteCount + 1];
            System.arraycopy(messageBytes, 0, newBytes, 0, byteCount);
            newBytes[byteCount] = 0x00;
            messageBytes = newBytes;
            byteCount++;
            log.debug("[{}] 补零处理后字节数: {}", libraryName, byteCount);
        }

        // 计算需写入的寄存器数量（每2字节占1个寄存器）
        int registerCount = byteCount / 2;
        log.debug("[{}] 寄存器数量: {}", libraryName, registerCount);

        sendToCharacterLibrary(libraryName, propertyStart, dataStart, unitId,
                messageBytes, byteCount, registerCount);
    }

    private void sendToCharacterLibrary(
            String libraryName,
            short propertyStart,
            short dataStart,
            byte unitId,
            byte[] messageBytes,
            int byteCount,
            int registerCount
    ) throws IOException {
        byte[] request = buildModbusRequest(unitId, propertyStart, dataStart,
                messageBytes, byteCount, registerCount);
        log.debug("[{}] 构造Modbus请求: {}", libraryName, byteArrayToHexString(request));

        try (Socket socket = new Socket()) {
            // 连接显示器
            socket.connect(new java.net.InetSocketAddress(ipAddress, port), CONNECT_TIMEOUT_MS);
            socket.setSoTimeout(READ_TIMEOUT_MS);
            log.info("[{}] 成功连接到显示器: {}:{}", libraryName, ipAddress, port);

            try (OutputStream os = socket.getOutputStream();
                 InputStream is = socket.getInputStream()) {
                // 发送请求
                os.write(request);
                os.flush();
                log.debug("[{}] 请求已发送，等待响应", libraryName);

                // 读取响应
                byte[] response = new byte[1024];
                int bytesRead = is.read(response);
                if (bytesRead > 0) {
                    log.info("[{}] 收到响应: {}", libraryName, byteArrayToHexString(response, bytesRead));
                } else {
                    log.warn("[{}] 未收到有效响应", libraryName);
                }
            }

            log.info("[{}] 消息发送成功", libraryName);

        } catch (SocketTimeoutException e) {
            log.error("[{}] 连接或读取超时 - {}:{}", libraryName, ipAddress, port, e);
            throw e;
        } catch (IOException e) {
            log.error("[{}] 网络异常 - {}:{}", libraryName, ipAddress, port, e);
            throw e;
        }
    }

    private byte[] buildModbusRequest(
            byte unitId,
            short propertyStart,
            short dataStart,
            byte[] messageBytes,
            int byteCount,
            int registerCount
    ) {
        short totalRegisters = (short) (5 + registerCount); // 5控制寄存器 + 数据寄存器
        int pduLength = 1 + 2 + 2 + 1 + 10 + byteCount;
        int totalLength = 6 + 1 + pduLength;
        byte[] request = new byte[totalLength];
        int offset = 0;

        // Modbus TCP 头部
        request[offset++] = 0x00; request[offset++] = 0x01;
        request[offset++] = 0x00; request[offset++] = 0x00;
        request[offset++] = (byte) ((1 + pduLength) >> 8);
        request[offset++] = (byte) ((1 + pduLength) & 0xFF);
        request[offset++] = unitId;

        // PDU 部分（地址高字节在前）
        request[offset++] = 0x10;
        request[offset++] = (byte) (propertyStart >> 8); // 属性起始地址高字节
        request[offset++] = (byte) (propertyStart & 0xFF); // 属性起始地址低字节
        request[offset++] = (byte) (totalRegisters >> 8); // 总寄存器数高字节
        request[offset++] = (byte) (totalRegisters & 0xFF); // 总寄存器数低字节
        request[offset++] = (byte) (10 + byteCount); // 字节计数

        // 控制寄存器（0-4）
        request[offset++] = 0x00; request[offset++] = 0x01; // 地址0：左移
        request[offset++] = 0x00; request[offset++] = 0x01; // 地址1：颜色（红色）
        request[offset++] = 0x00; request[offset++] = 0x00; // 地址2：保留
        request[offset++] = 0x00; request[offset++] = 0x05; // 地址3：速度
        request[offset++] = 0x00; request[offset++] = (byte) byteCount; // 地址4：数据长度（字节数）

        // 数据寄存器（动态填充）
        System.arraycopy(messageBytes, 0, request, offset, byteCount);

        log.debug("构造Modbus请求 - 总长度: {}字节, 寄存器总数: {}", totalLength, totalRegisters);
        return request;
    }

    /**
     * 字节数组转十六进制字符串（辅助方法）
     */
    private String byteArrayToHexString(byte[] bytes) {
        return byteArrayToHexString(bytes, bytes.length);
    }

    /**
     * 字节数组转十六进制字符串（辅助方法）
     */
    private String byteArrayToHexString(byte[] bytes, int length) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append(String.format("%02X ", bytes[i] & 0xFF));
        }
        return sb.toString().trim();
    }
}